<?php
require_once ('Zend/Controller/Plugin/Abstract.php');

/**
 * Cacheing plugin for Zend Framework applications
 *
 * @author Kovács Tamás
 * @category Smithy
 * @package Smithy_Plugin
 */
class Smithy_Plugin_Cache extends Zend_Controller_Plugin_Abstract
{
    /**
     * @var Zend_Cache
     */
    protected $_cache = NULL;

    /**
     * The current request's cache key
     * @var string
     */
    protected $_key = '';

    /**
     * @var bool
     */
    public static $doNotCache = FALSE;

    /**
     * Constructor: Initialize cache.
     *
     * @param array|Zend_Config $options
     * @return void
     * @throws Exception
     */
    function __construct ($options)
    {
        if ($options instanceof Zend_Config) {
        	$options = $options->toArray();
        }

        if (!is_array($options)) {
            throw new Exception('Invalid cache options; must be an array or a Zend_Config object');
        }

        if (array('frontend', 'backend', 'frontendOptions', 'backendOptions') != array_keys($options)) {
            throw new Exception('Invalid cache options provided');
        }

        $options['frontendOptions']['automatic_serialization'] = TRUE;

        $this->_cache = Zend_Cache::factory(
            $options['frontend'],
            $options['backend'],
            $options['frontendOptions'],
            $options['backendOptions']
        );
    }

    /**
     * Start caching.
     *
     * Determine if we have a cache hit. If we do than we pull the data from the cache and return it as response,
     * otherwise we start caching.
     *
     * @param Zend_Controller_Request_Abstract $request
     * @return void
     */
    public function dispatchLoopStartup(Zend_Controller_Request_Abstract $request)
    {
    	if (!$request->isGet()) {
    	    self::$doNotCache = TRUE;
    	    return;
    	}

    	$path = $request->getPathInfo();

    	$prefix = Zend_Auth::getInstance()->hasIdentity() ? md5(Zend_Auth::getInstance()->getIdentity()->id) : 'guest';

    	$this->_key = $prefix . '_' . md5($path);

    	if (FALSE !== ($response = $this->getCache())) {
    	    Phly_PubSub::publish('log', 'Loading from cache: ' . $this->_key);
    	    $response->sendResponse();
    	    exit();
    	}
    }

    /**
     * Store cache
     *
     * @return void
     */
    public function dispatchLoopShutDown()
    {
    	if (self::$doNotCache
    	   || $this->getResponse()->isRedirect()
    	   || (NULL === $this->_key)
        ) {
            return;
        }

        Phly_PubSub::publish('log', 'Caching: ' . $this->_key);
        $this->_cache->save($this->getResponse(), $this->_key);
    }

    /**
     * Get cache
     *
     * @return bool
     */
    public function getCache()
    {
    	return $this->_cache->load($this->_key);
    }

}
